package archer.framework.test.support.bean;


import archer.framework.test.support.TestConfig;
import archer.framework.utils.RandomUtils;
import archer.framework.utils.ValidateUtils;
import jodd.introspector.ClassDescriptor;
import jodd.introspector.ClassIntrospector;
import jodd.introspector.FieldDescriptor;
import jodd.typeconverter.Convert;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 随机对象创建工具
 *
 * @author christ
 * @date 2015/9/7
 */
public class BeanCreator extends TestConfig {

    //--------------------------------------集合创建----------------------------------------------------

    public static String[] EXCLUDES;

    static {
        String excludes = getConfig("test.beanCreator.excludes");
        if (ValidateUtils.isNotEmpty(excludes)) {
            EXCLUDES = excludes.split(",");
        } else {
            EXCLUDES = new String[]{};
        }
    }

    /**
     * 随机填充对象的某些字段
     *
     * @param tClass
     * @param size
     * @param fields
     * @param <T>
     * @return
     */
    public static <T> List<T> randomWith(Class<T> tClass, int size, String... fields) {

        List<T> results = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            results.add(randomWith(tClass, fields));
        }
        return results;
    }

    public static <T> List<T> randomWithout(Class<T> tClass, int size, String... fields) {
        List<T> results = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            results.add(randomWithout(tClass, fields));
        }
        return results;
    }

    /**
     * 除了全局排除字段外随机填充对象的所有字段
     *
     * @param tClass
     * @param size
     * @param <T>
     * @return
     */
    public static <T> List<T> random(Class<T> tClass, int size) {
        List<T> results = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            results.add(random(tClass));
        }
        return results;
    }

    //--------------------------------------单个bean创建----------------------------------------------------

    /**
     * 随机填充对象的某些字段
     *
     * @param tClass
     * @param fields
     * @param <T>
     * @return
     */
    public static <T> T randomWith(Class<T> tClass, String... fields) {
        return random(tClass, true, fields);
    }

    /**
     * 随机填充对象并排除某些字段
     *
     * @param tClass
     * @param fields
     * @param <T>
     * @return
     */
    public static <T> T randomWithout(Class<T> tClass, String... fields) {
        return random(tClass, false, fields);
    }

    /**
     * 除了全局排除字段外随机填充对象的所有字段
     *
     * @param tClass
     * @param <T>
     * @return
     */
    public static <T> T random(Class<T> tClass) {
        return random(tClass, false, EXCLUDES);
    }

    //--------------------------------------内部实现----------------------------------------------------

    /**
     * 填充对象的所有字段
     *
     * @param tClass
     * @param include
     * @param fields
     * @param <T>
     * @return
     */
    private static <T> T random(Class<T> tClass, boolean include, String... fields) {

        List<String> fieldsList = Arrays.asList(fields);

        ClassDescriptor classDescriptor = ClassIntrospector.lookup(tClass);

        T result = null;
        try {
            result = tClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return result;
        }

        FieldDescriptor[] allFieldDescriptors = classDescriptor.getAllFieldDescriptors();

        if (ValidateUtils.isNotEmpty(allFieldDescriptors)) {
            for (FieldDescriptor each : allFieldDescriptors) {
                Class raw = each.getRawType();
                if (include && fieldsList.contains(each.getName())) {
                    invokeSetter(result, raw, each);
                }
                if (!include && !fieldsList.contains(each.getName())) {
                    invokeSetter(result, raw, each);
                }

            }
        }
        return result;
    }

    private static <T> T invokeSetter(T result, Class raw, FieldDescriptor field) {
        try {

            // 如果有默认值则不设置
            Object value = field.invokeGetter(result);
            if (value != null) {
                return result;
            }

            if (raw.isAssignableFrom(String.class)) {
                field.invokeSetter(result, RandomUtils.randomAlpha(8));
            }
            if (raw.isAssignableFrom(long.class) || raw.isAssignableFrom(Long.class)) {
                field.invokeSetter(result, Convert.toLong(RandomUtils.randomNumeric(4)));
            }
            if (raw.isAssignableFrom(int.class) || raw.isAssignableFrom(Integer.class)) {
                field.invokeSetter(result, Convert.toInteger(RandomUtils.randomNumeric(4)));
            }
            if (raw.isAssignableFrom(BigDecimal.class)) {
                field.invokeSetter(result, Convert.toBigDecimal(RandomUtils.randomNumeric(4)));
            }
            if (raw.isAssignableFrom(Date.class)) {
                field.invokeSetter(result, new Date(System.currentTimeMillis()));
            }
            if (raw.isAssignableFrom(java.sql.Date.class)) {
                field.invokeSetter(result, new java.sql.Date(System.currentTimeMillis()));
            }
            if (raw.isAssignableFrom(Timestamp.class)) {
                field.invokeSetter(result, new Timestamp(System.currentTimeMillis()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

}
